package com.jagochan.imchat.module.websocket;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.jagochan.imchat.module.websocket.domain.enums.WSReqTypeEnum;
import com.jagochan.imchat.module.websocket.domain.vo.req.WSBaseReq;
import com.jagochan.imchat.module.websocket.service.WebSocketService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

@Slf4j
@ChannelHandler.Sharable
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private WebSocketService webSocketService;

    /**
     * 通道活跃
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        webSocketService = SpringUtil.getBean(WebSocketService.class);
        webSocketService.connect(ctx.channel());
    }

    /**
     * 通道不活跃（用户主动下线）
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        userOffline(ctx.channel());
    }

    /**
     * 用户触发事件
     *
     * @param evt 事件类型
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            log.info("握手完成");
            String token = ctx.channel().attr(AttributeKey.valueOf("token")).get().toString();
            if (StrUtil.isNotBlank(token)) {
                webSocketService.authorize(ctx.channel(), (String) token);
            }
        } else if (evt instanceof IdleStateEvent) { // 空闲状态事件
            IdleStateEvent idleStateEvent = ((IdleStateEvent) evt);
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                log.info("读空闲");
                // 用户下线
                userOffline(ctx.channel());
            }

        }
        super.userEventTriggered(ctx, evt);
    }

    /**
     * 用户下线
     */
    public void userOffline(Channel channel) {
        // 清除在线用户和Channel的缓存
        webSocketService.remove(channel);
        // 断开连接
        channel.close();
    }

    /**
     * 客户端通过ws向服务器端发送信息后会来到这里
     *
     * @param channelHandlerContext 可用户向客户端返回数据
     * @param textWebSocketFrame    客户端传给服务端的数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext,
                                TextWebSocketFrame textWebSocketFrame) throws Exception {
        String text = textWebSocketFrame.text();
        WSBaseReq wsBaseReq = JSONUtil.toBean(text, WSBaseReq.class);

        WSReqTypeEnum wsReqTypeEnum = WSReqTypeEnum.of(wsBaseReq.getType());
        if (Objects.isNull(wsReqTypeEnum)) {
            log.info("未知的请求类型");
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("未知的请求类型"));
            return;
        }
        switch (wsReqTypeEnum) {
            case LOGIN_QRCODE:
                log.info("请求登陆二维码");
                webSocketService.requestLoginQrCodeUrl(channelHandlerContext.channel());
                break;
            case HEARTBEAT:
                log.info("心跳检测");
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("你要心跳检测"));
                break;
            case AUTHORIZE:
                log.info("登陆认证");
                webSocketService.authorize(channelHandlerContext.channel(), wsBaseReq.getData());
                break;
        }
    }

}
